home *** CD-ROM | disk | FTP | other *** search
- /* Time-stamp: "Sat 30 Jan 1999, 13:01:51 EST by drk@sgi.com (David Kaelbling)"
- *
- * A stripped-down version of skeylogin, intended for use as an IRIX
- * login SITECHECK program. A SITECHECK program must be executable,
- * owned by root, and not writable by others.
- *
- * Usage: keyauth name [ remhost [ rusername ] ]
- * Prompt for an s/key password and authenticate it. Return status:
- * 0: Success; user was authenticated, log in.
- * 1: Failure; exit login.
- * 2: Failure; try again (don't exit login).
- * other: Use normal UNIX authentication.
- */
-
- #ifdef _BSD_SIGNALS
- #undef _BSD_SIGNALS
- #endif
- #ifdef _BSD_COMPAT
- #undef _BSD_COMPAT
- #endif
-
- #include <sys/param.h>
- #include <sys/types.h>
-
- #include <limits.h>
- #include <unistd.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <fcntl.h>
- #include <netdb.h>
- #include <netinet/in.h>
- #include <pwd.h>
- #include <stdio.h>
- #include <string.h>
- #include <termio.h>
-
- #include "skey.h"
-
- #define SCPYN(a, b) strncpy(a, b, sizeof(a)), a[sizeof(a)-1]='\0'
-
- #define NMAX 32 /* Should be >= sizeof(utmpx.ut_user) */
-
- #define SITE_OK 0
- #define SITE_FAIL 1
- #define SITE_AGAIN 2
- #define SITE_CONTINUE 3
-
- /*
- * This bounds the time given to login. We initialize it here
- * so it can be patched on machines where it's too small.
- */
- int timeout = 300;
-
- char *readskeypass(char *buf, int n);
- static void timedout(void);
- static int authfile(char *host);
- static int isaddr(register char *s);
- static long aton(register char *s);
- static int rdnets(long host);
-
- void
- main(int argc, char *argv[])
- {
- struct passwd *pwd;
- char lusername[NMAX+1];
- char host[MAXHOSTNAMELEN];
- char rusername[NMAX+1];
- char skeyprompt[80];
- struct skey skey;
- int skey_status;
- char buf[LINE_MAX];
-
- *host = *rusername = *skeyprompt = '\0';
-
- /* Save the username */
- if (argc > 1) {
- SCPYN(lusername, argv[1]);
- if (*lusername == '-') {
- puts("user names may not start with '-'.");
- exit(SITE_FAIL);
- }
- argc--;
- argv++;
- } else {
- puts("missing user name argument.");
- exit(SITE_FAIL);
- }
-
- /* Save the remotehost */
- if (argc > 1) {
- SCPYN(host, argv[1]);
- if (*host == '-') {
- puts("remote host name may not start with '-'.");
- exit(SITE_FAIL);
- }
- argc--;
- argv++;
- }
-
- /* Save the remote username */
- if (argc > 1) {
- SCPYN(rusername, argv[1]);
- if (*rusername == '-') {
- puts("remote user names may not start with '-'.");
- exit(SITE_FAIL);
- }
- argc--;
- argv++;
- }
-
- /* Check for extra args. */
- if (argc > 1) {
- puts("too many arguments.");
- exit(SITE_FAIL);
- }
-
-
- /* If this is a local login use normal password authentication. */
- if (authfile(host))
- exit(SITE_CONTINUE);
-
- /* Punt back to login if this user does not have a password. */
- pwd = getpwnam(lusername);
- if (pwd && *pwd->pw_passwd == '\0')
- exit(SITE_CONTINUE);
-
-
- /* Issue an s/key challenge */
- if (feof(stdin)) exit(SITE_FAIL);
- skey_status = skeychallenge(&skey, lusername, skeyprompt);
- printf("%s\n", skeyprompt);
- printf("(s/key required)\nPassword:");
- fflush(stdout);
-
- /* Read password */
- signal(SIGALRM, timedout);
- alarm(timeout);
- readskeypass(buf, sizeof(buf));
- alarm(0);
-
- /* Did S/Key authentication succeed? */
- if (skey_status == 0 && skeyverify(&skey, buf) == 0 &&
- pwd && *pwd->pw_passwd != '*' && *pwd->pw_passwd != '#') {
- if (skey.n < 5)
- puts("Warning! Change password soon");
- exit(SITE_OK);
- }
-
- puts("Login incorrect");
- exit(SITE_AGAIN);
- }
-
- static void
- timedout(void)
- {
- printf("\nLogin timed out after %d seconds\n", timeout);
- exit(SITE_FAIL);
- }
-
- /*
- * Turn host into an IP address and then look it up in the authorization
- * database to determine if ordinary password logins are OK.
- */
- static int
- authfile(char *host)
- {
- long n;
- struct hostent *hp;
- char **lp;
-
- if (*host == '\0') {
- /* Local login, okay */
- return 1;
- }
-
- if (isaddr(host)) {
- n = aton(host);
- return rdnets(n);
- } else {
- hp = gethostbyname(host);
- if (hp == NULL) {
- printf("Unknown host %s\n", host);
- return 0;
- }
- for (lp = hp->h_addr_list; *lp != NULL; lp++) {
- memcpy((char *)&n, *lp, sizeof(n));
- n = ntohl(n);
- if (rdnets(n))
- return 1;
- }
- return 0;
- }
- }
-
- /*
- * Return non-zero if "host" is permitted to use normal password login.
- */
- static int
- rdnets(long host)
- {
- FILE *fp;
- char buf[LINE_MAX], *cp;
- long pattern, mask;
- int permit_it;
-
- fp = fopen("/etc/skey.access", "r");
- if (fp == NULL)
- return 0;
-
- while(fgets(buf, sizeof(buf), fp), !feof(fp)) {
- if (*buf == '#')
- continue; /* Comment */
-
- cp = strtok(buf, " \t");
- if (cp == NULL)
- continue;
-
- /* two choices: permit or deny */
- if (strncasecmp(cp, "permit", 4) == 0) {
- permit_it = 1;
- } else if (strncasecmp(cp, "deny" , 4) == 0) {
- permit_it = 0;
- } else {
- continue; /* ignore this it is not permit/deny */
- }
-
- cp = strtok(NULL, " \t");
- if (cp == NULL)
- continue; /* Invalid line */
- pattern = aton(cp);
-
- cp = strtok(NULL, " \t");
- if (cp == NULL)
- continue; /* Invalid line */
- mask = aton(cp);
-
- if ((host & mask) == pattern) {
- fclose(fp);
- return permit_it;
- }
- }
-
- fclose(fp);
- return 0;
- }
-
- /*
- * Return non-zero if string appears to be an IP address in dotted decimal;
- * return 0 otherwise (i.e., if string is a domain name)
- */
- static int
- isaddr(register char *s)
- {
- char c;
-
- if (s == NULL)
- return 1; /* Can't happen */
-
- while((c = *s++) != '\0') {
- if (c != '[' && c != ']' && !isdigit(c) && c != '.')
- return 0;
- }
- return 1;
- }
-
- /*
- * Convert Internet address in ascii dotted-decimal format (44.0.0.1) to
- * binary IP address
- */
- static long
- aton(register char *s)
- {
- long n = 0;
- register int i;
-
- if (s == NULL)
- return 0;
-
- for (i = 24; i >= 0; i -= 8) {
- /* Skip any leading stuff (e.g., spaces, '[') */
- while(*s != '\0' && !isdigit(*s))
- s++;
- if (*s == '\0')
- break;
-
- n |= atol(s) << i;
- if ((s = strchr(s, '.')) == NULL)
- break;
- s++;
- }
-
- return n;
- }
-